/**
 * The MOSES project, model based software engineering of networked embedded systems.
 * 
 * Copyright (C) 2010-2013, University of Applied Sciences Wildau,
 * Telematics Research Group, http://www.tm.th-wildau.de/research-group
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 3 of the
 * License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see <http://www.gnu.org/licenses>.
 * 
 * Contributors:
 *     University of Applied Sciences Wildau - initial API and implementation
 * 
 * If you are interested in a commercial license please contact us via
 * e-mail: ralf.vandenhouten@th-wildau.de.
 */
package de.thwildau.tm.moses.abnf.generator;

import com.google.common.base.Objects;
import com.google.common.collect.Iterables;
import com.google.inject.Inject;
import de.thwildau.tm.moses.abnf.abnf.Rule;
import de.thwildau.tm.moses.abnf.generator.AbnfReadState;
import de.thwildau.tm.moses.abnf.generator.JavaTemplates;
import de.thwildau.tm.moses.abnf.generator.ModelInferrer;
import de.thwildau.tm.moses.abnf.generator.ModelUtil;
import de.thwildau.tm.moses.abnf.generator.NameResolver;
import de.thwildau.tm.moses.abnf.generator.model.AbnfAlternation;
import de.thwildau.tm.moses.abnf.generator.model.AbnfAttribute;
import de.thwildau.tm.moses.abnf.generator.model.AbnfCharValue;
import de.thwildau.tm.moses.abnf.generator.model.AbnfCoreRule;
import de.thwildau.tm.moses.abnf.generator.model.AbnfElementField;
import de.thwildau.tm.moses.abnf.generator.model.AbnfRepeat;
import de.thwildau.tm.moses.abnf.generator.model.AbnfRuleClass;
import de.thwildau.tm.moses.abnf.generator.model.impl.AbnfRuleClassImpl;
import java.util.Arrays;
import java.util.List;
import org.apache.log4j.Logger;
import org.eclipse.emf.codegen.util.ImportManager;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.xtend2.lib.StringConcatenation;
import org.eclipse.xtext.generator.IFileSystemAccess;
import org.eclipse.xtext.generator.IGenerator;
import org.eclipse.xtext.naming.QualifiedName;
import org.eclipse.xtext.util.Pair;
import org.eclipse.xtext.util.Tuples;
import org.eclipse.xtext.xbase.lib.Extension;
import org.eclipse.xtext.xbase.lib.Functions.Function0;
import org.eclipse.xtext.xbase.lib.IntegerRange;
import org.eclipse.xtext.xbase.lib.IterableExtensions;
import org.eclipse.xtext.xbase.lib.IteratorExtensions;
import org.eclipse.xtext.xbase.lib.Procedures.Procedure2;
import org.eclipse.xtext.xbase.lib.StringExtensions;

/**
 * This generator generates Java classes for the given ABNF resource. It generates
 * a Java class for each rule that is defined in the ABNF file. It does not generate
 * class for core-rule.
 * This class uses a ModelInferrer to infer the ABNF grammar model into an intermediate
 * model that is used for the code generation. This generator refers to library classes
 * that are located in the 'de.thwildau.tm.moses.abnf.io' package.
 */
@SuppressWarnings("all")
public class AbnfGenerator implements IGenerator {
  private final static Logger LOG = new Function0<Logger>() {
    public Logger apply() {
      Logger _logger = Logger.getLogger(AbnfGenerator.class);
      return _logger;
    }
  }.apply();
  
  @Inject
  private ModelInferrer modelInferrer;
  
  @Inject
  private NameResolver nameResolver;
  
  @Inject
  @Extension
  private ModelUtil modelUtil;
  
  public void doGenerate(final Resource resource, final IFileSystemAccess fsa) {
    final String packageName = this.nameResolver.getPackageName(resource);
    boolean _isAbnfCoreResource = this.nameResolver.isAbnfCoreResource(resource);
    boolean _not = (!_isAbnfCoreResource);
    if (_not) {
      TreeIterator<EObject> _allContents = resource.getAllContents();
      Iterable<EObject> _iterable = IteratorExtensions.<EObject>toIterable(_allContents);
      final Iterable<Rule> allRules = Iterables.<Rule>filter(_iterable, Rule.class);
      final List<AbnfRuleClass> ruleClasses = this.modelInferrer.createModel(allRules);
      for (final AbnfRuleClass rc : ruleClasses) {
        {
          String _className = rc.getClassName();
          QualifiedName fqn = this.nameResolver.getFqn(packageName, _className);
          String javaFileName = this.nameResolver.getJavaFilename(fqn);
          CharSequence _generateClassFile = this.generateClassFile(rc, fqn);
          fsa.generateFile(javaFileName, _generateClassFile);
          this.generateEnums(fsa, rc);
        }
      }
    }
  }
  
  public void generateEnums(final IFileSystemAccess fsa, final AbnfRuleClass model) {
    List<AbnfElementField> _elements = model.getElements();
    Iterable<AbnfAlternation> _filter = Iterables.<AbnfAlternation>filter(_elements, AbnfAlternation.class);
    for (final AbnfAlternation ruleRef : _filter) {
      {
        Rule _rule = ((AbnfRuleClassImpl) model).getRule();
        Resource _eResource = _rule.eResource();
        String _type = ruleRef.getType();
        String _plus = (_type + "Enum");
        QualifiedName javaFqn = this.nameResolver.getFqn(_eResource, _plus);
        String javaFileName = this.nameResolver.getJavaFilename(javaFqn);
        String _plus_1 = ("Generate " + javaFqn);
        String _plus_2 = (_plus_1 + " to ");
        String _plus_3 = (_plus_2 + javaFileName);
        System.out.println(_plus_3);
        CharSequence _generateEnumFile = this.generateEnumFile(ruleRef, javaFqn);
        fsa.generateFile(javaFileName, _generateEnumFile);
      }
    }
  }
  
  public CharSequence generateClassFile(final AbnfRuleClass rc, final QualifiedName fqn) {
    StringConcatenation _builder = new StringConcatenation();
    CharSequence _generateFileComment = JavaTemplates.generateFileComment();
    _builder.append(_generateFileComment, "");
    _builder.newLineIfNotEmpty();
    CharSequence _generatePackage = JavaTemplates.generatePackage(fqn);
    _builder.append(_generatePackage, "");
    _builder.newLineIfNotEmpty();
    String _packageName = JavaTemplates.getPackageName(fqn);
    String _lastSegment = fqn.getLastSegment();
    ImportManager _importManager = new ImportManager(_packageName, _lastSegment);
    ImportManager importManager = _importManager;
    _builder.newLineIfNotEmpty();
    CharSequence body = this.toClassBody(rc, importManager);
    _builder.newLineIfNotEmpty();
    String _computeSortedImports = importManager.computeSortedImports();
    _builder.append(_computeSortedImports, "");
    _builder.newLineIfNotEmpty();
    _builder.newLine();
    CharSequence _generateClassComment = JavaTemplates.generateClassComment(rc);
    _builder.append(_generateClassComment, "");
    _builder.newLineIfNotEmpty();
    _builder.append(body, "");
    _builder.newLineIfNotEmpty();
    return _builder;
  }
  
  public CharSequence generateEnumFile(final AbnfAlternation<? extends Object> alternation, final QualifiedName fqn) {
    StringConcatenation _builder = new StringConcatenation();
    CharSequence _generateFileComment = JavaTemplates.generateFileComment();
    _builder.append(_generateFileComment, "");
    _builder.newLineIfNotEmpty();
    CharSequence _generatePackage = JavaTemplates.generatePackage(fqn);
    _builder.append(_generatePackage, "");
    _builder.newLineIfNotEmpty();
    String _packageName = JavaTemplates.getPackageName(fqn);
    String _lastSegment = fqn.getLastSegment();
    ImportManager _importManager = new ImportManager(_packageName, _lastSegment);
    ImportManager importManager = _importManager;
    _builder.newLineIfNotEmpty();
    CharSequence body = this.toEnumBody(alternation, importManager);
    _builder.newLineIfNotEmpty();
    String _computeSortedImports = importManager.computeSortedImports();
    _builder.append(_computeSortedImports, "");
    _builder.newLineIfNotEmpty();
    _builder.newLine();
    CharSequence _generateClassComment = JavaTemplates.generateClassComment(alternation);
    _builder.append(_generateClassComment, "");
    _builder.newLineIfNotEmpty();
    _builder.append(body, "");
    _builder.newLineIfNotEmpty();
    return _builder;
  }
  
  public CharSequence toClassBody(final AbnfRuleClass rc, final ImportManager im) {
    StringConcatenation _builder = new StringConcatenation();
    _builder.append("public class ");
    String _className = rc.getClassName();
    _builder.append(_className, "");
    String _extendsStatement = this.toExtendsStatement(rc, im);
    _builder.append(_extendsStatement, "");
    _builder.append(" implements ");
    String _import = this.getImport(im, "de.thwildau.tm.moses.abnf.io.Transmitable");
    _builder.append(_import, "");
    _builder.append(" {");
    _builder.newLineIfNotEmpty();
    _builder.append("\t");
    _builder.newLine();
    _builder.append("\t");
    CharSequence _fields = this.toFields(rc, im);
    _builder.append(_fields, "	");
    _builder.newLineIfNotEmpty();
    _builder.append("\t");
    _builder.newLine();
    _builder.append("\t");
    CharSequence _setterGetterMethods = this.toSetterGetterMethods(rc, im);
    _builder.append(_setterGetterMethods, "	");
    _builder.newLineIfNotEmpty();
    _builder.append("\t");
    _builder.newLine();
    _builder.append("\t");
    CharSequence _readMethod = this.toReadMethod(rc, im);
    _builder.append(_readMethod, "	");
    _builder.newLineIfNotEmpty();
    _builder.append("\t");
    _builder.newLine();
    _builder.append("\t");
    CharSequence _writeMethod = this.toWriteMethod(rc, im);
    _builder.append(_writeMethod, "	");
    _builder.newLineIfNotEmpty();
    _builder.append("\t");
    _builder.newLine();
    _builder.append("\t");
    String _className_1 = rc.getClassName();
    CharSequence _stringMethod = this.toStringMethod(rc, _className_1, im);
    _builder.append(_stringMethod, "	");
    _builder.newLineIfNotEmpty();
    _builder.append("\t");
    _builder.newLine();
    _builder.append("\t");
    CharSequence _compareMethods = this.toCompareMethods(rc, im);
    _builder.append(_compareMethods, "	");
    _builder.newLineIfNotEmpty();
    _builder.append("}");
    _builder.newLine();
    return _builder;
  }
  
  /**
   * If AbnfRuleClass has a superClass attribute, then generate a extends statement
   * to the class body.
   */
  private String toExtendsStatement(final AbnfRuleClass rc, final ImportManager im) {
    AbnfRuleClass _superClass = rc.getSuperClass();
    boolean _notEquals = (!Objects.equal(_superClass, null));
    if (_notEquals) {
      AbnfRuleClass _superClass_1 = rc.getSuperClass();
      String _className = _superClass_1.getClassName();
      String _import = this.getImport(im, _className);
      return (" extends " + _import);
    } else {
      return "";
    }
  }
  
  /**
   * generate a enum by AbnfCharValues and a complex enum by AbnfAttributes
   */
  public CharSequence toEnumBody(final AbnfAlternation<? extends Object> alternation, final ImportManager im) {
    CharSequence _xifexpression = null;
    List<? extends AbnfElementField> _values = alternation.getValues();
    int _size = _values.size();
    boolean _greaterThan = (_size > 0);
    if (_greaterThan) {
      List<? extends AbnfElementField> _values_1 = alternation.getValues();
      final AbnfElementField instance = _values_1.get(0);
      if ((instance instanceof AbnfCharValue)) {
        return this.toEnumBodyOfAbnfCharValue(alternation, im);
      } else {
        if ((instance instanceof AbnfAttribute)) {
          return this.toEnumBodyOfAbnfAttribute(alternation, im);
        } else {
          String _plus = ("Could not generate enum class for Element " + instance);
          String _plus_1 = (_plus + " of type ");
          Class<? extends AbnfElementField> _class = instance.getClass();
          String _name = _class.getName();
          String _plus_2 = (_plus_1 + _name);
          String _plus_3 = (_plus_2 + ". Must be a AbnfCharValue or AbnfAttribute.");
          AbnfGenerator.LOG.warn(_plus_3);
          return "";
        }
      }
    }
    return _xifexpression;
  }
  
  private CharSequence toEnumBodyOfAbnfCharValue(final AbnfAlternation<? extends Object> alternation, final ImportManager im) {
    StringConcatenation _builder = new StringConcatenation();
    _builder.append("public enum ");
    String _type = alternation.getType();
    _builder.append(_type, "");
    _builder.append(" implements ");
    String _import = this.getImport(im, "de.thwildau.tm.moses.abnf.io.ValueEnum");
    _builder.append(_import, "");
    _builder.append(" {");
    _builder.newLineIfNotEmpty();
    _builder.newLine();
    StringConcatenation _stringConcatenation = new StringConcatenation();
    final StringConcatenation enumEntries = _stringConcatenation;
    _builder.newLineIfNotEmpty();
    List<? extends AbnfElementField> _values = alternation.getValues();
    Iterable<AbnfCharValue> _filter = Iterables.<AbnfCharValue>filter(_values, AbnfCharValue.class);
    final Procedure2<AbnfCharValue,Integer> _function = new Procedure2<AbnfCharValue,Integer>() {
        public void apply(final AbnfCharValue ele, final Integer i) {
          List<? extends AbnfElementField> _values = alternation.getValues();
          int _size = _values.size();
          int _minus = (_size - 1);
          boolean _equals = ((i).intValue() == _minus);
          CharSequence _enumField = AbnfGenerator.this.toEnumField(((AbnfCharValue) ele), _equals);
          enumEntries.append(_enumField);
        }
      };
    IterableExtensions.<AbnfCharValue>forEach(_filter, _function);
    _builder.newLineIfNotEmpty();
    _builder.append("\t");
    _builder.append(enumEntries, "	");
    _builder.newLineIfNotEmpty();
    _builder.append("\t");
    _builder.newLine();
    _builder.append("\t");
    _builder.append("private ");
    String _import_1 = this.getImport(im, "java.lang.String");
    _builder.append(_import_1, "	");
    _builder.append(" value;");
    _builder.newLineIfNotEmpty();
    _builder.append("\t");
    _builder.newLine();
    _builder.append("\t");
    _builder.append("private ");
    String _type_1 = alternation.getType();
    _builder.append(_type_1, "	");
    _builder.append("(");
    String _import_2 = this.getImport(im, "java.lang.String");
    _builder.append(_import_2, "	");
    _builder.append(" value) {");
    _builder.newLineIfNotEmpty();
    _builder.append("\t\t");
    _builder.append("this.value = value;");
    _builder.newLine();
    _builder.append("\t");
    _builder.append("}");
    _builder.newLine();
    _builder.append("\t");
    _builder.newLine();
    _builder.append("\t");
    _builder.append("@");
    String _import_3 = this.getImport(im, "java.lang.Override");
    _builder.append(_import_3, "	");
    _builder.newLineIfNotEmpty();
    _builder.append("\t");
    _builder.append("public ");
    String _import_4 = this.getImport(im, "java.lang.String");
    _builder.append(_import_4, "	");
    _builder.append(" getValue() {");
    _builder.newLineIfNotEmpty();
    _builder.append("\t\t");
    _builder.append("return value;");
    _builder.newLine();
    _builder.append("\t");
    _builder.append("}");
    _builder.newLine();
    _builder.append("}");
    _builder.newLine();
    return _builder;
  }
  
  private CharSequence toEnumBodyOfAbnfAttribute(final AbnfAlternation<? extends Object> alternation, final ImportManager im) {
    StringConcatenation _builder = new StringConcatenation();
    _builder.append("public class ");
    String _type = alternation.getType();
    _builder.append(_type, "");
    _builder.append(" implements ");
    String _import = this.getImport(im, "de.thwildau.tm.moses.abnf.io.Transmitable");
    _builder.append(_import, "");
    _builder.append("{");
    _builder.newLineIfNotEmpty();
    _builder.append("\t\t");
    _builder.newLine();
    _builder.append("\t\t");
    _builder.append("public enum Value implements ");
    String _import_1 = this.getImport(im, "de.thwildau.tm.moses.abnf.io.ValueEnum");
    _builder.append(_import_1, "		");
    _builder.append(", ");
    String _type_1 = alternation.getType();
    String _plus = ("de.thwildau.tm.moses.abnf.io.ComplexValueEnum<" + _type_1);
    String _plus_1 = (_plus + ">");
    String _import_2 = this.getImport(im, _plus_1);
    _builder.append(_import_2, "		");
    _builder.append(" {");
    _builder.newLineIfNotEmpty();
    _builder.append("\t");
    StringConcatenation _stringConcatenation = new StringConcatenation();
    final StringConcatenation enumEntries = _stringConcatenation;
    _builder.newLineIfNotEmpty();
    _builder.append("\t");
    List<? extends AbnfElementField> _values = alternation.getValues();
    Iterable<AbnfAttribute> _filter = Iterables.<AbnfAttribute>filter(_values, AbnfAttribute.class);
    final Procedure2<AbnfAttribute,Integer> _function = new Procedure2<AbnfAttribute,Integer>() {
        public void apply(final AbnfAttribute ele, final Integer i) {
          List<? extends AbnfElementField> _values = alternation.getValues();
          int _size = _values.size();
          int _minus = (_size - 1);
          boolean _equals = ((i).intValue() == _minus);
          CharSequence _enumField = AbnfGenerator.this.toEnumField(((AbnfAttribute) ele), _equals);
          enumEntries.append(_enumField);
        }
      };
    IterableExtensions.<AbnfAttribute>forEach(_filter, _function);
    _builder.newLineIfNotEmpty();
    _builder.append("\t\t\t");
    _builder.append(enumEntries, "			");
    _builder.newLineIfNotEmpty();
    _builder.append("\t\t\t");
    _builder.newLine();
    _builder.append("\t\t\t");
    _builder.append("private final String id;");
    _builder.newLine();
    _builder.append("\t\t\t");
    _builder.append("private ");
    String _type_2 = alternation.getType();
    String _firstUpper = StringExtensions.toFirstUpper(_type_2);
    String _import_3 = this.getImport(im, _firstUpper);
    _builder.append(_import_3, "			");
    _builder.append(" ");
    String _type_3 = alternation.getType();
    String _firstLower = StringExtensions.toFirstLower(_type_3);
    String _import_4 = this.getImport(im, _firstLower);
    _builder.append(_import_4, "			");
    _builder.append(";");
    _builder.newLineIfNotEmpty();
    _builder.append("\t\t\t");
    _builder.newLine();
    _builder.append("\t\t\t");
    _builder.append("private Value(");
    String _import_5 = this.getImport(im, "java.lang.String");
    _builder.append(_import_5, "			");
    _builder.append(" id) {");
    _builder.newLineIfNotEmpty();
    _builder.append("\t\t\t\t");
    _builder.append("this.id = id;");
    _builder.newLine();
    _builder.append("\t\t\t");
    _builder.append("}");
    _builder.newLine();
    _builder.append("\t\t\t");
    _builder.newLine();
    _builder.append("\t\t\t");
    _builder.append("public ");
    String _import_6 = this.getImport(im, "java.lang.String");
    _builder.append(_import_6, "			");
    _builder.append(" getValue() {");
    _builder.newLineIfNotEmpty();
    _builder.append("\t\t\t\t");
    _builder.append("return id;");
    _builder.newLine();
    _builder.append("\t\t\t");
    _builder.append("}");
    _builder.newLine();
    _builder.append("\t\t\t");
    _builder.newLine();
    _builder.append("\t\t\t");
    _builder.append("@");
    String _import_7 = this.getImport(im, "java.lang.Override");
    _builder.append(_import_7, "			");
    _builder.newLineIfNotEmpty();
    _builder.append("\t\t\t");
    _builder.append("public ");
    String _type_4 = alternation.getType();
    String _firstUpper_1 = StringExtensions.toFirstUpper(_type_4);
    _builder.append(_firstUpper_1, "			");
    _builder.append(" getComplexValue() {");
    _builder.newLineIfNotEmpty();
    _builder.append("\t\t\t\t");
    _builder.append("return ");
    String _type_5 = alternation.getType();
    String _firstLower_1 = StringExtensions.toFirstLower(_type_5);
    _builder.append(_firstLower_1, "				");
    _builder.append(";");
    _builder.newLineIfNotEmpty();
    _builder.append("\t\t\t");
    _builder.append("}");
    _builder.newLine();
    _builder.append("\t\t\t");
    _builder.newLine();
    _builder.append("\t\t\t");
    _builder.append("public void setComplexValue(");
    String _type_6 = alternation.getType();
    String _firstUpper_2 = StringExtensions.toFirstUpper(_type_6);
    _builder.append(_firstUpper_2, "			");
    _builder.append(" ");
    String _type_7 = alternation.getType();
    String _firstLower_2 = StringExtensions.toFirstLower(_type_7);
    _builder.append(_firstLower_2, "			");
    _builder.append(") {");
    _builder.newLineIfNotEmpty();
    _builder.append("\t\t\t\t");
    _builder.append("this.");
    String _type_8 = alternation.getType();
    String _firstLower_3 = StringExtensions.toFirstLower(_type_8);
    _builder.append(_firstLower_3, "				");
    _builder.append(" = ");
    String _type_9 = alternation.getType();
    String _firstLower_4 = StringExtensions.toFirstLower(_type_9);
    _builder.append(_firstLower_4, "				");
    _builder.append(";");
    _builder.newLineIfNotEmpty();
    _builder.append("\t\t\t");
    _builder.append("}");
    _builder.newLine();
    _builder.append("\t\t");
    _builder.append("}");
    _builder.newLine();
    _builder.append("\t\t");
    _builder.newLine();
    _builder.append("\t\t");
    _builder.append("private Value value;");
    _builder.newLine();
    _builder.append("\t\t");
    _builder.newLine();
    _builder.append("\t\t");
    _builder.append("public Value getValue(){");
    _builder.newLine();
    _builder.append("\t\t\t");
    _builder.append("return value;");
    _builder.newLine();
    _builder.append("\t\t");
    _builder.append("}");
    _builder.newLine();
    _builder.append("\t\t");
    _builder.newLine();
    _builder.append("\t\t");
    CharSequence _complexEnumRead = this.toComplexEnumRead(alternation, im);
    _builder.append(_complexEnumRead, "		");
    _builder.newLineIfNotEmpty();
    _builder.append("\t\t");
    _builder.newLine();
    _builder.append("\t\t");
    _builder.newLine();
    _builder.append("\t\t");
    CharSequence _complexEnumWrite = this.toComplexEnumWrite(alternation, im);
    _builder.append(_complexEnumWrite, "		");
    _builder.newLineIfNotEmpty();
    _builder.append("\t\t");
    _builder.newLine();
    _builder.append("\t\t");
    _builder.newLine();
    _builder.append("\t\t");
    CharSequence _complexEnumToString = this.toComplexEnumToString(alternation, im);
    _builder.append(_complexEnumToString, "		");
    _builder.newLineIfNotEmpty();
    _builder.append("\t");
    _builder.append("}");
    _builder.newLine();
    return _builder;
  }
  
  /**
   * generate the toString method for the complex Enum
   * TODO implement
   */
  public CharSequence toComplexEnumToString(final AbnfAlternation<? extends Object> alternation, final ImportManager im) {
    StringConcatenation _builder = new StringConcatenation();
    _builder.append("@");
    String _import = this.getImport(im, "java.lang.Override");
    _builder.append(_import, "");
    _builder.newLineIfNotEmpty();
    _builder.append("public String toString() {");
    _builder.newLine();
    _builder.append("\t");
    _builder.append("return \"\" + value.getComplexValue();");
    _builder.newLine();
    _builder.append("}");
    _builder.newLine();
    return _builder;
  }
  
  /**
   * generate the write method for the complex Enum
   * TODO implement
   */
  public CharSequence toComplexEnumWrite(final AbnfAlternation<? extends Object> alternation, final ImportManager im) {
    StringConcatenation _builder = new StringConcatenation();
    _builder.append("@");
    String _import = this.getImport(im, "java.lang.Override");
    _builder.append(_import, "");
    _builder.newLineIfNotEmpty();
    _builder.append("public void write(");
    String _import_1 = this.getImport(im, "java.io.DataOutput");
    _builder.append(_import_1, "");
    _builder.append(" out) throws IOException {");
    _builder.newLineIfNotEmpty();
    _builder.append("\t");
    _builder.append("// TODO Auto-generated method stub");
    _builder.newLine();
    _builder.append("}");
    _builder.newLine();
    return _builder;
  }
  
  /**
   * generate the read method for a alternation with attributes in a Enum
   */
  public CharSequence toComplexEnumRead(final AbnfAlternation<? extends Object> alternation, final ImportManager im) {
    StringConcatenation _builder = new StringConcatenation();
    _builder.append("@");
    String _import = this.getImport(im, "java.lang.Override");
    _builder.append(_import, "");
    _builder.newLineIfNotEmpty();
    _builder.append("public void read(");
    String _import_1 = this.getImport(im, "java.io.DataInput");
    _builder.append(_import_1, "");
    _builder.append(" in) throws ");
    String _import_2 = this.getImport(im, "java.io.IOException");
    _builder.append(_import_2, "");
    _builder.append(" {");
    _builder.newLineIfNotEmpty();
    _builder.append("\t");
    _builder.append("value = ");
    String _import_3 = this.getImport(im, "de.thwildau.tm.moses.abnf.io.AbnfCoder");
    _builder.append(_import_3, "	");
    _builder.append(".decode(in, Value.values());");
    _builder.newLineIfNotEmpty();
    _builder.append("\t");
    String _type = alternation.getType();
    String _firstUpper = StringExtensions.toFirstUpper(_type);
    _builder.append(_firstUpper, "	");
    _builder.append(" ");
    String _type_1 = alternation.getType();
    String _firstLower = StringExtensions.toFirstLower(_type_1);
    _builder.append(_firstLower, "	");
    _builder.append(" = null;");
    _builder.newLineIfNotEmpty();
    _builder.append("\t");
    StringConcatenation _stringConcatenation = new StringConcatenation();
    final StringConcatenation enumSwitch = _stringConcatenation;
    _builder.newLineIfNotEmpty();
    _builder.append("\t");
    _builder.append("switch (value) {");
    _builder.newLine();
    _builder.append("\t\t");
    StringConcatenation _builder_1 = new StringConcatenation();
    _builder_1.append("default:");
    _builder_1.newLine();
    _builder_1.append("\t");
    _builder_1.append("throw new ");
    String _import_4 = this.getImport(im, "java.io.IOException");
    _builder_1.append(_import_4, "	");
    _builder_1.append("(\"Unknown ");
    String _type_2 = alternation.getType();
    String _firstLower_1 = StringExtensions.toFirstLower(_type_2);
    _builder_1.append(_firstLower_1, "	");
    _builder_1.append("\");");
    _builder_1.newLineIfNotEmpty();
    enumSwitch.append(_builder_1);
    _builder.newLineIfNotEmpty();
    _builder.append("\t\t");
    List<? extends AbnfElementField> _values = alternation.getValues();
    Iterable<AbnfAttribute> _filter = Iterables.<AbnfAttribute>filter(_values, AbnfAttribute.class);
    final Procedure2<AbnfAttribute,Integer> _function = new Procedure2<AbnfAttribute,Integer>() {
        public void apply(final AbnfAttribute ele, final Integer i) {
          StringConcatenation _builder = new StringConcatenation();
          _builder.append("case ");
          String _type = ele.getType();
          _builder.append(_type, "");
          _builder.append(":");
          _builder.newLineIfNotEmpty();
          _builder.append("\t");
          String _type_1 = alternation.getType();
          String _firstLower = StringExtensions.toFirstLower(_type_1);
          _builder.append(_firstLower, "	");
          _builder.append(" = new ");
          String _type_2 = ele.getType();
          _builder.append(_type_2, "	");
          _builder.append("();");
          _builder.newLineIfNotEmpty();
          _builder.append("\t");
          _builder.append("break;");
          _builder.newLine();
          enumSwitch.append(_builder);
        }
      };
    IterableExtensions.<AbnfAttribute>forEach(_filter, _function);
    _builder.newLineIfNotEmpty();
    _builder.append("\t\t");
    _builder.append(enumSwitch, "		");
    _builder.newLineIfNotEmpty();
    _builder.append("\t");
    _builder.append("}");
    _builder.newLine();
    _builder.append("\t");
    _builder.newLine();
    _builder.append("\t");
    _builder.append("if(");
    String _type_3 = alternation.getType();
    String _firstLower_2 = StringExtensions.toFirstLower(_type_3);
    _builder.append(_firstLower_2, "	");
    _builder.append(" != null){");
    _builder.newLineIfNotEmpty();
    _builder.append("\t\t");
    String _type_4 = alternation.getType();
    String _firstLower_3 = StringExtensions.toFirstLower(_type_4);
    _builder.append(_firstLower_3, "		");
    _builder.append(".read(in);");
    _builder.newLineIfNotEmpty();
    _builder.append("\t\t");
    _builder.append("value.setComplexValue(");
    String _type_5 = alternation.getType();
    String _firstLower_4 = StringExtensions.toFirstLower(_type_5);
    _builder.append(_firstLower_4, "		");
    _builder.append(");");
    _builder.newLineIfNotEmpty();
    _builder.append("\t");
    _builder.append("}");
    _builder.newLine();
    _builder.append("}");
    _builder.newLine();
    return _builder;
  }
  
  public CharSequence toEnumField(final String element, final boolean isLast) {
    StringConcatenation _builder = new StringConcatenation();
    String _enumName = JavaTemplates.toEnumName(element);
    _builder.append(_enumName, "");
    _builder.append("(\"");
    _builder.append(element, "");
    _builder.append("\")");
    CharSequence _enumFieldDelimiter = JavaTemplates.enumFieldDelimiter(isLast);
    _builder.append(_enumFieldDelimiter, "");
    _builder.newLineIfNotEmpty();
    return _builder;
  }
  
  public CharSequence toEnumField(final AbnfAttribute element, final boolean isLast) {
    StringConcatenation _builder = new StringConcatenation();
    String _type = element.getType();
    String _enumName = JavaTemplates.toEnumName(_type);
    _builder.append(_enumName, "");
    _builder.append("(\"");
    String _type_1 = element.getType();
    _builder.append(_type_1, "");
    _builder.append("\")");
    CharSequence _enumFieldDelimiter = JavaTemplates.enumFieldDelimiter(isLast);
    _builder.append(_enumFieldDelimiter, "");
    _builder.newLineIfNotEmpty();
    return _builder;
  }
  
  public CharSequence toEnumField(final AbnfCharValue element, final boolean isLast) {
    StringConcatenation _builder = new StringConcatenation();
    String _value = element.getValue();
    String _enumName = JavaTemplates.toEnumName(_value);
    _builder.append(_enumName, "");
    _builder.append("(\"");
    String _value_1 = element.getValue();
    _builder.append(_value_1, "");
    _builder.append("\")");
    CharSequence _enumFieldDelimiter = JavaTemplates.enumFieldDelimiter(isLast);
    _builder.append(_enumFieldDelimiter, "");
    _builder.newLineIfNotEmpty();
    return _builder;
  }
  
  public CharSequence toFields(final AbnfRuleClass model, final ImportManager im) {
    StringConcatenation _builder = new StringConcatenation();
    _builder.append("// begin field section");
    _builder.newLine();
    {
      List<AbnfElementField> _elements = model.getElements();
      Iterable<AbnfAttribute> _filter = Iterables.<AbnfAttribute>filter(_elements, AbnfAttribute.class);
      for(final AbnfAttribute ruleRef : _filter) {
        _builder.append("/** field for rule ");
        String _name = ruleRef.getName();
        _builder.append(_name, "");
        _builder.append(" */");
        _builder.newLineIfNotEmpty();
        Pair<String,String> typeRef = this.toTypeReference(ruleRef, im);
        _builder.newLineIfNotEmpty();
        _builder.append("private ");
        String _first = typeRef.getFirst();
        _builder.append(_first, "");
        _builder.append(" ");
        String _name_1 = ruleRef.getName();
        _builder.append(_name_1, "");
        String _second = typeRef.getSecond();
        _builder.append(_second, "");
        _builder.append(";");
        _builder.newLineIfNotEmpty();
      }
    }
    _builder.append("// end field section");
    _builder.newLine();
    return _builder;
  }
  
  public CharSequence toSetterGetterMethods(final AbnfRuleClass model, final ImportManager im) {
    StringConcatenation _builder = new StringConcatenation();
    _builder.append("// begin setter getter section");
    _builder.newLine();
    {
      List<AbnfElementField> _elements = model.getElements();
      Iterable<AbnfAttribute> _filter = Iterables.<AbnfAttribute>filter(_elements, AbnfAttribute.class);
      for(final AbnfAttribute ruleRef : _filter) {
        Pair<String,String> typeRef = this.toTypeReference(ruleRef, im);
        _builder.newLineIfNotEmpty();
        _builder.append("public void set");
        String _name = ruleRef.getName();
        String _firstUpper = StringExtensions.toFirstUpper(_name);
        _builder.append(_firstUpper, "");
        _builder.append("(");
        String _first = typeRef.getFirst();
        _builder.append(_first, "");
        _builder.append(" ");
        String _name_1 = ruleRef.getName();
        _builder.append(_name_1, "");
        _builder.append(") {");
        _builder.newLineIfNotEmpty();
        _builder.append("\t");
        _builder.append("this.");
        String _name_2 = ruleRef.getName();
        _builder.append(_name_2, "	");
        _builder.append(" = ");
        String _name_3 = ruleRef.getName();
        _builder.append(_name_3, "	");
        _builder.append(";");
        _builder.newLineIfNotEmpty();
        _builder.append("}");
        _builder.newLine();
        _builder.newLine();
        _builder.append("public ");
        String _first_1 = typeRef.getFirst();
        _builder.append(_first_1, "");
        _builder.append(" get");
        String _name_4 = ruleRef.getName();
        String _firstUpper_1 = StringExtensions.toFirstUpper(_name_4);
        _builder.append(_firstUpper_1, "");
        _builder.append("() {");
        _builder.newLineIfNotEmpty();
        _builder.append("\t");
        _builder.append("return this.");
        String _name_5 = ruleRef.getName();
        _builder.append(_name_5, "	");
        _builder.append(";");
        _builder.newLineIfNotEmpty();
        _builder.append("}\t\t");
        _builder.newLine();
      }
    }
    _builder.append("// end setter getter section");
    _builder.newLine();
    return _builder;
  }
  
  public Pair<String,String> toTypeReference(final AbnfAttribute ruleRef, final ImportManager im) {
    boolean _and = false;
    AbnfRepeat _repeat = ruleRef.getRepeat();
    boolean _isLoop = this.modelUtil.isLoop(_repeat);
    if (!_isLoop) {
      _and = false;
    } else {
      String _type = ruleRef.getType();
      boolean _isCoreRuleReference = ModelUtil.isCoreRuleReference(_type);
      boolean _not = (!_isCoreRuleReference);
      _and = (_isLoop && _not);
    }
    if (_and) {
      String _type_1 = ruleRef.getType();
      String _import = this.getImport(im, _type_1);
      String _plus = ("<" + _import);
      String genericParam = (_plus + ">");
      String _import_1 = this.getImport(im, "java.util.List");
      String type = (_import_1 + genericParam);
      String _import_2 = this.getImport(im, "java.util.ArrayList");
      String _plus_1 = (" = new " + _import_2);
      String _plus_2 = (_plus_1 + genericParam);
      String initializer = (_plus_2 + "()");
      return Tuples.<String, String>create(type, initializer);
    } else {
      String _type_2 = ruleRef.getType();
      String type_1 = this.getImport(im, _type_2);
      return Tuples.<String, String>create(type_1, "");
    }
  }
  
  public CharSequence toReadMethod(final AbnfRuleClass model, final ImportManager im) {
    StringConcatenation _builder = new StringConcatenation();
    _builder.append("@");
    String _import = this.getImport(im, "java.lang.Override");
    _builder.append(_import, "");
    _builder.newLineIfNotEmpty();
    _builder.append("public void read(");
    String _import_1 = this.getImport(im, "java.io.DataInput");
    _builder.append(_import_1, "");
    _builder.append(" in) throws ");
    String _import_2 = this.getImport(im, "java.io.IOException");
    _builder.append(_import_2, "");
    _builder.append(" {");
    _builder.newLineIfNotEmpty();
    _builder.append("\t");
    List<AbnfElementField> _elements = model.getElements();
    StringConcatenation _read = this.toRead(_elements, im);
    _builder.append(_read, "	");
    _builder.newLineIfNotEmpty();
    _builder.append("}");
    _builder.newLine();
    return _builder;
  }
  
  public StringConcatenation toRead(final List<AbnfElementField> elements, final ImportManager im) {
    StringConcatenation _stringConcatenation = new StringConcatenation();
    StringConcatenation con = _stringConcatenation;
    AbnfReadState lastState = null;
    int _size = elements.size();
    int _minus = (_size - 1);
    IntegerRange _upTo = new IntegerRange(0, _minus);
    for (final Integer i : _upTo) {
      {
        AbnfElementField _get = elements.get((i).intValue());
        int _plus = ((i).intValue() + 1);
        AbnfElementField _elementSave = this.<AbnfElementField>getElementSave(elements, _plus);
        AbnfReadState _abnfReadState = new AbnfReadState(lastState, _get, _elementSave);
        AbnfReadState state = _abnfReadState;
        AbnfElementField _current = state.getCurrent();
        CharSequence _readEntry = this.toReadEntry(_current, state, im);
        con.append(_readEntry);
        lastState = state;
      }
    }
    return con;
  }
  
  public CharSequence toWriteMethod(final AbnfRuleClass model, final ImportManager im) {
    StringConcatenation _builder = new StringConcatenation();
    _builder.append("@");
    String _import = this.getImport(im, "java.lang.Override");
    _builder.append(_import, "");
    _builder.newLineIfNotEmpty();
    _builder.append("public void write(");
    String _import_1 = this.getImport(im, "java.io.DataOutput");
    _builder.append(_import_1, "");
    _builder.append(" out) throws ");
    String _import_2 = this.getImport(im, "java.io.IOException");
    _builder.append(_import_2, "");
    _builder.append(" {");
    _builder.newLineIfNotEmpty();
    {
      List<AbnfElementField> _elements = model.getElements();
      for(final AbnfElementField ele : _elements) {
        _builder.append("\t");
        CharSequence _writeEntry = this.toWriteEntry(ele, im);
        _builder.append(_writeEntry, "	");
        _builder.newLineIfNotEmpty();
      }
    }
    _builder.append("}");
    _builder.newLine();
    return _builder;
  }
  
  public CharSequence toStringMethod(final AbnfRuleClass model, final String className, final ImportManager im) {
    StringConcatenation _builder = new StringConcatenation();
    _builder.append("@");
    String _import = this.getImport(im, "java.lang.Override");
    _builder.append(_import, "");
    _builder.newLineIfNotEmpty();
    _builder.append("public String toString() {");
    _builder.newLine();
    _builder.append("\t");
    String _import_1 = this.getImport(im, "java.lang.StringBuilder");
    _builder.append(_import_1, "	");
    _builder.append(" builder = new ");
    String _import_2 = this.getImport(im, "java.lang.StringBuilder");
    _builder.append(_import_2, "	");
    _builder.append("();");
    _builder.newLineIfNotEmpty();
    _builder.append("\t");
    _builder.append("builder.append(\"");
    _builder.append(className, "	");
    _builder.append("\");");
    _builder.newLineIfNotEmpty();
    _builder.append("\t");
    StringConcatenation _stringConcatenation = new StringConcatenation();
    final StringConcatenation buffer = _stringConcatenation;
    _builder.newLineIfNotEmpty();
    _builder.append("\t");
    List<AbnfElementField> _elements = model.getElements();
    Iterable<AbnfAttribute> _filter = Iterables.<AbnfAttribute>filter(_elements, AbnfAttribute.class);
    final Procedure2<AbnfAttribute,Integer> _function = new Procedure2<AbnfAttribute,Integer>() {
        public void apply(final AbnfAttribute ele, final Integer i) {
          String _xifexpression = null;
          boolean _equals = ((i).intValue() == 0);
          if (_equals) {
            StringConcatenation _builder = new StringConcatenation();
            _builder.append("builder.append(\" [\")");
            _xifexpression = _builder.toString();
          } else {
            StringConcatenation _builder_1 = new StringConcatenation();
            _builder_1.append("builder.append(\" ,\")");
            _xifexpression = _builder_1.toString();
          }
          String prefix = _xifexpression;
          buffer.append(prefix);
          StringConcatenation _builder_2 = new StringConcatenation();
          _builder_2.append(".append(\"");
          String _name = ele.getName();
          _builder_2.append(_name, "");
          _builder_2.append("=\")");
          buffer.append(_builder_2);
          StringConcatenation _builder_3 = new StringConcatenation();
          _builder_3.append(".append(");
          String _name_1 = ele.getName();
          _builder_3.append(_name_1, "");
          _builder_3.append(");");
          buffer.append(_builder_3);
          buffer.newLineIfNotEmpty();
        }
      };
    IterableExtensions.<AbnfAttribute>forEach(_filter, _function);
    _builder.newLineIfNotEmpty();
    _builder.append("\t");
    _builder.append(buffer, "	");
    _builder.newLineIfNotEmpty();
    _builder.append("\t");
    _builder.append("builder.append(\"]\\n\");");
    _builder.newLine();
    _builder.append("\t");
    _builder.append("return builder.toString();");
    _builder.newLine();
    _builder.append("}");
    _builder.newLine();
    return _builder;
  }
  
  public CharSequence toCompareMethods(final AbnfRuleClass model, final ImportManager im) {
    StringConcatenation _builder = new StringConcatenation();
    {
      List<AbnfElementField> _elements = model.getElements();
      Iterable<AbnfAttribute> _filter = Iterables.<AbnfAttribute>filter(_elements, AbnfAttribute.class);
      for(final AbnfAttribute att : _filter) {
        _builder.append("public boolean isEqual(");
        String _type = att.getType();
        String _import = this.getImport(im, _type);
        _builder.append(_import, "");
        _builder.append(" ");
        String _name = att.getName();
        _builder.append(_name, "");
        _builder.append(") {");
        _builder.newLineIfNotEmpty();
        _builder.append("\t");
        _builder.append("return this.");
        String _name_1 = att.getName();
        _builder.append(_name_1, "	");
        _builder.append(".equals(");
        String _name_2 = att.getName();
        _builder.append(_name_2, "	");
        _builder.append(");");
        _builder.newLineIfNotEmpty();
        _builder.append("}");
        _builder.newLine();
      }
    }
    return _builder;
  }
  
  protected CharSequence _toWriteEntry(final AbnfCharValue ele, final ImportManager im) {
    StringConcatenation _builder = new StringConcatenation();
    AbnfRepeat _repeat = ele.getRepeat();
    CharSequence _forLoop = this.toForLoop(_repeat, true);
    _builder.append(_forLoop, "");
    _builder.newLineIfNotEmpty();
    String _import = this.getImport(im, "de.thwildau.tm.moses.abnf.io.AbnfCoder");
    _builder.append(_import, "");
    _builder.append(".encode(out, \"");
    String _value = ele.getValue();
    _builder.append(_value, "");
    _builder.append("\");");
    _builder.newLineIfNotEmpty();
    AbnfRepeat _repeat_1 = ele.getRepeat();
    CharSequence _forLoop_1 = this.toForLoop(_repeat_1, false);
    _builder.append(_forLoop_1, "");
    _builder.newLineIfNotEmpty();
    return _builder;
  }
  
  protected CharSequence _toWriteEntry(final AbnfAttribute ele, final ImportManager im) {
    StringConcatenation _builder = new StringConcatenation();
    String _import = this.getImport(im, "de.thwildau.tm.moses.abnf.io.AbnfCoder");
    _builder.append(_import, "");
    _builder.append(".encode(out, ");
    String _name = ele.getName();
    _builder.append(_name, "");
    _builder.append(");");
    _builder.newLineIfNotEmpty();
    return _builder;
  }
  
  protected CharSequence _toWriteEntry(final AbnfCoreRule ele, final ImportManager im) {
    StringConcatenation _builder = new StringConcatenation();
    AbnfRepeat _repeat = ele.getRepeat();
    CharSequence _forLoop = this.toForLoop(_repeat, true);
    _builder.append(_forLoop, "");
    _builder.newLineIfNotEmpty();
    String _import = this.getImport(im, "de.thwildau.tm.moses.abnf.io.AbnfCoder");
    _builder.append(_import, "");
    _builder.append(".encode(out, ");
    String _import_1 = this.getImport(im, "de.thwildau.tm.moses.abnf.io.CoreRules");
    _builder.append(_import_1, "");
    _builder.append(".");
    String _ruleName = ele.getRuleName();
    _builder.append(_ruleName, "");
    _builder.append(");");
    _builder.newLineIfNotEmpty();
    AbnfRepeat _repeat_1 = ele.getRepeat();
    CharSequence _forLoop_1 = this.toForLoop(_repeat_1, false);
    _builder.append(_forLoop_1, "");
    _builder.newLineIfNotEmpty();
    return _builder;
  }
  
  protected CharSequence _toReadEntry(final AbnfCharValue ele, final AbnfReadState state, final ImportManager im) {
    StringConcatenation _builder = new StringConcatenation();
    {
      boolean _wasCurrentElementRead = state.wasCurrentElementRead();
      boolean _not = (!_wasCurrentElementRead);
      if (_not) {
        String _import = this.getImport(im, "de.thwildau.tm.moses.abnf.io.AbnfCoder");
        _builder.append(_import, "");
        _builder.append(".");
        boolean _isFirst = state.isFirst();
        String _decodeMethod = this.getDecodeMethod(_isFirst);
        _builder.append(_decodeMethod, "");
        _builder.append("(in, \"");
        String _value = ele.getValue();
        _builder.append(_value, "");
        _builder.append("\");");
        _builder.newLineIfNotEmpty();
      }
    }
    return _builder;
  }
  
  protected CharSequence _toReadEntry(final AbnfAttribute ele, final AbnfReadState state, final ImportManager im) {
    StringConcatenation _builder = new StringConcatenation();
    {
      boolean _wasCurrentElementRead = state.wasCurrentElementRead();
      boolean _not = (!_wasCurrentElementRead);
      if (_not) {
        {
          boolean _and = false;
          AbnfRepeat _repeat = ele.getRepeat();
          boolean _isInfinite = this.modelUtil.isInfinite(_repeat);
          if (!_isInfinite) {
            _and = false;
          } else {
            String _type = ele.getType();
            boolean _isCoreRuleReference = ModelUtil.isCoreRuleReference(_type);
            boolean _not_1 = (!_isCoreRuleReference);
            _and = (_isInfinite && _not_1);
          }
          if (_and) {
            _builder.append("try {");
            _builder.newLine();
            _builder.append("\t");
            _builder.append("while(true) {");
            _builder.newLine();
            _builder.append("\t\t");
            String _type_1 = ele.getType();
            final String typeRef = this.getImport(im, _type_1);
            _builder.newLineIfNotEmpty();
            _builder.append("\t\t");
            String _type_2 = ele.getType();
            final String localName = _type_2.toLowerCase();
            _builder.newLineIfNotEmpty();
            _builder.append("\t\t");
            _builder.append(typeRef, "		");
            _builder.append(" ");
            _builder.append(localName, "		");
            _builder.append(" = new ");
            _builder.append(typeRef, "		");
            _builder.append("();");
            _builder.newLineIfNotEmpty();
            _builder.append("\t\t");
            _builder.append(localName, "		");
            _builder.append(".read(in);");
            _builder.newLineIfNotEmpty();
            _builder.append("\t\t");
            String _name = ele.getName();
            _builder.append(_name, "		");
            _builder.append(".add(");
            _builder.append(localName, "		");
            _builder.append(");");
            _builder.newLineIfNotEmpty();
            _builder.append("\t");
            _builder.append("}");
            _builder.newLine();
            _builder.append("} catch(");
            String _import = this.getImport(im, "de.thwildau.tm.moses.abnf.io.ParseException");
            _builder.append(_import, "");
            _builder.append(" e) {");
            _builder.newLineIfNotEmpty();
            _builder.append("\t");
            String _import_1 = this.getImport(im, "de.thwildau.tm.moses.abnf.io.AbnfCoder");
            _builder.append(_import_1, "	");
            _builder.append(".checkDecode(e.getLastBuffer(), in, ");
            CharSequence _decodeRef = this.getDecodeRef(state, im);
            _builder.append(_decodeRef, "	");
            _builder.append(");");
            _builder.newLineIfNotEmpty();
            _builder.append("}");
            _builder.newLine();
          } else {
            String _import_2 = this.getImport(im, "java.lang.String");
            _builder.append(_import_2, "");
            _builder.append(" ");
            String _name_1 = ele.getName();
            _builder.append(_name_1, "");
            _builder.append(" = ");
            String _import_3 = this.getImport(im, "de.thwildau.tm.moses.abnf.io.AbnfCoder");
            _builder.append(_import_3, "");
            _builder.append(".decodeUntil(in, ");
            CharSequence _decodeRef_1 = this.getDecodeRef(state, im);
            _builder.append(_decodeRef_1, "");
            _builder.append(");");
            _builder.newLineIfNotEmpty();
            _builder.append("this.");
            String _name_2 = ele.getName();
            _builder.append(_name_2, "");
            _builder.append(" = ");
            String _type_3 = ele.getType();
            String _import_4 = this.getImport(im, _type_3);
            _builder.append(_import_4, "");
            _builder.append(".valueOf(");
            String _name_3 = ele.getName();
            _builder.append(_name_3, "");
            _builder.append(");");
            _builder.newLineIfNotEmpty();
          }
        }
      }
    }
    return _builder;
  }
  
  protected CharSequence _toReadEntry(final AbnfAlternation<? extends Object> ele, final AbnfReadState state, final ImportManager im) {
    StringConcatenation _builder = new StringConcatenation();
    {
      boolean _wasCurrentElementRead = state.wasCurrentElementRead();
      boolean _not = (!_wasCurrentElementRead);
      if (_not) {
        _builder.append("this.");
        String _name = ele.getName();
        _builder.append(_name, "");
        _builder.append(" = ");
        String _import = this.getImport(im, "de.thwildau.tm.moses.abnf.io.AbnfCoder");
        _builder.append(_import, "");
        _builder.append(".decode(in, ");
        String _type = ele.getType();
        _builder.append(_type, "");
        _builder.append(".values());");
        _builder.newLineIfNotEmpty();
      }
    }
    return _builder;
  }
  
  protected CharSequence _toReadEntry(final AbnfCoreRule ele, final AbnfReadState state, final ImportManager im) {
    StringConcatenation _builder = new StringConcatenation();
    {
      boolean _wasCurrentElementRead = state.wasCurrentElementRead();
      boolean _not = (!_wasCurrentElementRead);
      if (_not) {
        String _import = this.getImport(im, "de.thwildau.tm.moses.abnf.io.AbnfCoder");
        _builder.append(_import, "");
        _builder.append(".");
        boolean _isFirst = state.isFirst();
        String _decodeMethod = this.getDecodeMethod(_isFirst);
        _builder.append(_decodeMethod, "");
        _builder.append("(in, ");
        String _import_1 = this.getImport(im, "de.thwildau.tm.moses.abnf.io.CoreRules");
        _builder.append(_import_1, "");
        _builder.append(".");
        String _ruleName = ele.getRuleName();
        _builder.append(_ruleName, "");
        _builder.append(");");
        _builder.newLineIfNotEmpty();
      }
    }
    return _builder;
  }
  
  public CharSequence getDecodeRef(final AbnfReadState state, final ImportManager im) {
    final AbnfElementField next = state.getNext();
    boolean _notEquals = (!Objects.equal(next, null));
    if (_notEquals) {
      return this.getDecodeRef0(next, im);
    }
    return null;
  }
  
  protected CharSequence _getDecodeRef0(final AbnfAttribute ele, final ImportManager im) {
    StringConcatenation _builder = new StringConcatenation();
    _builder.append("UNKNOWN");
    return _builder;
  }
  
  protected CharSequence _getDecodeRef0(final AbnfCharValue ele, final ImportManager im) {
    StringConcatenation _builder = new StringConcatenation();
    _builder.append("\"");
    String _value = ele.getValue();
    _builder.append(_value, "");
    _builder.append("\"");
    return _builder;
  }
  
  protected CharSequence _getDecodeRef0(final AbnfCoreRule ele, final ImportManager im) {
    StringConcatenation _builder = new StringConcatenation();
    String _import = this.getImport(im, "de.thwildau.tm.moses.abnf.io.CoreRules");
    _builder.append(_import, "");
    _builder.append(".");
    String _ruleName = ele.getRuleName();
    _builder.append(_ruleName, "");
    return _builder;
  }
  
  public String getDecodeMethod(final boolean doTryCheck) {
    if (doTryCheck) {
      return "tryCheckDecode";
    } else {
      return "checkDecode";
    }
  }
  
  public CharSequence toForLoop(final AbnfRepeat repeat, final boolean begin) {
    StringConcatenation _builder = new StringConcatenation();
    {
      boolean _isLoop = this.modelUtil.isLoop(repeat);
      if (_isLoop) {
        {
          if (begin) {
            {
              boolean _isInfinite = this.modelUtil.isInfinite(repeat);
              if (_isInfinite) {
                _builder.append("for(;;)");
              } else {
                _builder.append("for(int i=0;i<");
                long _upperBound = repeat.getUpperBound();
                _builder.append(_upperBound, "");
                _builder.append(";i++)");
              }
            }
            _builder.append(" {");
            _builder.newLineIfNotEmpty();
          } else {
            _builder.append("}");
            _builder.newLine();
          }
        }
      }
    }
    return _builder;
  }
  
  public String getImport(final ImportManager im, final String qualifiedName) {
    return im.getImportedName(qualifiedName, true);
  }
  
  /**
   * Returns the element at the specified index in the list. Returns null, if the index
   * is out of the range or the element at the specified index is null and the list permits
   * null element.
   * This is the save method of java.util.List.get(i), that doesn't throw an IndexOutOfBoundsException
   */
  public <T extends Object> T getElementSave(final List<T> list, final int index) {
    boolean _and = false;
    boolean _greaterEqualsThan = (index >= 0);
    if (!_greaterEqualsThan) {
      _and = false;
    } else {
      int _size = list.size();
      boolean _lessThan = (index < _size);
      _and = (_greaterEqualsThan && _lessThan);
    }
    if (_and) {
      return list.get(index);
    }
    return null;
  }
  
  public CharSequence toWriteEntry(final AbnfElementField ele, final ImportManager im) {
    if (ele instanceof AbnfAttribute) {
      return _toWriteEntry((AbnfAttribute)ele, im);
    } else if (ele instanceof AbnfCharValue) {
      return _toWriteEntry((AbnfCharValue)ele, im);
    } else if (ele instanceof AbnfCoreRule) {
      return _toWriteEntry((AbnfCoreRule)ele, im);
    } else {
      throw new IllegalArgumentException("Unhandled parameter types: " +
        Arrays.<Object>asList(ele, im).toString());
    }
  }
  
  public CharSequence toReadEntry(final AbnfElementField ele, final AbnfReadState state, final ImportManager im) {
    if (ele instanceof AbnfAlternation) {
      return _toReadEntry((AbnfAlternation<? extends Object>)ele, state, im);
    } else if (ele instanceof AbnfAttribute) {
      return _toReadEntry((AbnfAttribute)ele, state, im);
    } else if (ele instanceof AbnfCharValue) {
      return _toReadEntry((AbnfCharValue)ele, state, im);
    } else if (ele instanceof AbnfCoreRule) {
      return _toReadEntry((AbnfCoreRule)ele, state, im);
    } else {
      throw new IllegalArgumentException("Unhandled parameter types: " +
        Arrays.<Object>asList(ele, state, im).toString());
    }
  }
  
  public CharSequence getDecodeRef0(final AbnfElementField ele, final ImportManager im) {
    if (ele instanceof AbnfAttribute) {
      return _getDecodeRef0((AbnfAttribute)ele, im);
    } else if (ele instanceof AbnfCharValue) {
      return _getDecodeRef0((AbnfCharValue)ele, im);
    } else if (ele instanceof AbnfCoreRule) {
      return _getDecodeRef0((AbnfCoreRule)ele, im);
    } else {
      throw new IllegalArgumentException("Unhandled parameter types: " +
        Arrays.<Object>asList(ele, im).toString());
    }
  }
}
